using CSuperSocket.SocketBase;
using CSuperSocket.SocketBase.Protocol;
using System;
using System.Collections.Generic;
using System.Text;
using WebSvrUpdaterCore.Models;
using WebUpdaterAdminCore.Data;
using WebUpdaterAdminCore.SocketServer;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using WebUpdaterAdminCore.Models;
using Microsoft.Extensions.Caching.Memory;

namespace WebUpdaterAdminCore
{
    public class UpdaterSocketServerService : AppServer<UpdaterSocketSession, MsgPacket>, IDisposable
    {

        #region 公开成员
        public delegate void IISReqestDelegate(object sender, RequestArg arg);
        public delegate void IISResponeDelegate(object sender, ResponeArg arg);
        public event IISReqestDelegate IISReqestHandler;
        public event IISResponeDelegate IISResponeHandler; 
        #endregion

        #region 内部成员
        private Dictionary<string, string> _sessionClientId;
        private ApplicationDbContext _applicationDb;
        private IServiceScope _scope;
        private static IMemoryCache _receiveMsgCache = new MemoryCache(new MemoryCacheOptions());
        private const string _newClient = "#NEW#";
        private const string _cacheKeyPrefix = "_CACHE_PK_";
        #endregion

        /// <summary>
        /// 添加请求结果
        /// 缓存10分钟
        /// </summary>
        /// <param name="msgReceive">请求结果内容</param>
        public static void AddReceiveMsg(MsgReceiveModel msgReceive)
        {
            if (msgReceive == null) return;
            lock (_receiveMsgCache)
            {
                var result = _receiveMsgCache.Set(
                _cacheKeyPrefix+msgReceive.RequestId,
                msgReceive,
                new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(30)));              
            }
        }

        /// <summary>
        /// 获取请求结果
        /// </summary>
        /// <param name="requestId">请求id</param>
        /// <returns></returns>
        public static MsgReceiveModel GetReceiveMsg(string requestId)
        {
            return _receiveMsgCache.Get<MsgReceiveModel>(_cacheKeyPrefix+requestId);              
        }

        public static void UpdateReceiveMsg(MsgReceiveModel data)
        {
            if(data == null)
            {
                throw new ArgumentNullException("data参数不允许为null");
            }
            var key = _cacheKeyPrefix + data.RequestId;
            var cache = GetReceiveMsg(data.RequestId);
            if(cache != null)
            {
                _receiveMsgCache.Remove(key);
            }
            AddReceiveMsg(data);

        }
        /// <summary>
        /// Socket会话ID与客户端ID映射
        /// </summary>
        public Dictionary<string, string> SessionClientIds
        {
            get
            {
                return _sessionClientId;
            }
        }

        /// <summary>
        /// 返回客户端ID
        /// </summary>
        /// <param name="sessionId">Socket会话ID</param>
        /// <returns></returns>
        public string this[string sessionId]
        {
            get
            {
                string retStr = string.Empty;
                if (_sessionClientId != null)
                {
                    _sessionClientId.TryGetValue(sessionId, out retStr);
                }
                return retStr;
            }
        }

        public UpdaterSocketServerService()
          : base(new DefaultReceiveFilterFactory<DefaultBeginEndMarkReceiveFilter, MsgPacket>())
        {
            
            _sessionClientId = new Dictionary<string, string>();

        }

        ~UpdaterSocketServerService()
        {
            _scope.Dispose();
        }

        protected override void OnSessionClosed(UpdaterSocketSession session, CloseReason reason)
        {
            Logger.Info($"客户端{session.RemoteEndPoint},连接断开;理由:{reason}");
            base.OnSessionClosed(session, reason);
            session.Close(reason);
            try
            {
                _sessionClientId.Remove(session.SessionID);
                if (_applicationDb != null)
                {
                    var client = _applicationDb.ClientStatus.Find(session.ClientId);
                    if (client != null)
                    {
                        client.SessionId = "";
                        client.Connected = false;
                        _applicationDb.ClientStatus.Update(client);
                        _applicationDb.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("session关闭时出现异常,sessionID为{0};\r\n错误信息:{1}", session.SessionID, ex.Message);
            }

        }
        protected override void OnNewSessionConnected(UpdaterSocketSession session)
        {
            Logger.Info("新客户端连接上来" + session.RemoteEndPoint);
            base.OnNewSessionConnected(session);
            if (_sessionClientId != null && !_sessionClientId.ContainsKey(session.SessionID))
            {
                //新连接上的客户端ID默认设置#NEW#
                _sessionClientId.Add(session.SessionID, _newClient);
            }

        }
        protected override void ExecuteCommand(UpdaterSocketSession session, MsgPacket requestInfo)
        {
            var msgBody = Encoding.UTF8.GetString(requestInfo.Body);
            var key = requestInfo.Key;
            //session映射客户端ID
            if (_sessionClientId.ContainsKey(session.SessionID))
            {
                var clientId = _sessionClientId[session.SessionID];
                if (_newClient.Equals(clientId))
                {
                    session.ClientId = requestInfo.Uid;
                    _sessionClientId[session.SessionID] = requestInfo.Uid;
                }
                //新增或更新数据库中客户端信息
                if (_applicationDb != null)
                {
                    var client = _applicationDb.ClientInfos
                        .Include(ci => ci.ClientStatus)
                        .FirstOrDefault(w => w.ClientId == requestInfo.Uid);
                    if (client != null)
                    {
                        var clientStatus = client.ClientStatus;
                        //非连接状态才更新数据库,以此减少写数据库频率

                        if (clientStatus != null)
                        {
                            if (!clientStatus.Connected)
                            {
                                clientStatus.Id = requestInfo.Uid;
                                clientStatus.Connected = true;
                                clientStatus.LastActiveTime = DateTime.Now;
                                clientStatus.SessionId = session.SessionID;
                                clientStatus.StartTime = DateTime.Now;
                                clientStatus.ClientIP = session.RemoteEndPoint.Address.ToString();
                                _applicationDb.ClientStatus.Update(clientStatus);
                            }
                        }
                        else
                        {
                            var model = new Models.ClientState();
                            clientStatus.Id = requestInfo.Uid;
                            model.Connected = true;
                            model.LastActiveTime = DateTime.Now;
                            model.SessionId = session.SessionID;
                            model.StartTime = DateTime.Now;
                            model.ClientIP = session.RemoteEndPoint.Address.ToString();
                            _applicationDb.ClientStatus.Add(model);
                        }
                        _applicationDb.SaveChanges();

                    }
                    else
                    {
                        var clientStatus = new Models.ClientState
                        {
                            Id = requestInfo.Uid,
                            Connected = true,
                            SessionId = session.SessionID,
                            ClientIP = session.RemoteEndPoint.Address.ToString(),
                            LastActiveTime = DateTime.Now,
                            StartTime = DateTime.Now
                        };
                        _applicationDb.ClientStatus.Add(clientStatus);
                        client = new Models.ClientInfo
                        {
                            ClientId = requestInfo.Uid,
                            ClientName = requestInfo.Uid,
                            ClientStatus = clientStatus,
                            Group = DefaultGroup()
                        };
                        _applicationDb.ClientInfos.Add(client);
                        _applicationDb.SaveChanges();

                    }


                }
            }
            var clientHandle = new ClientCommandHandle(session, _applicationDb);
            var recvMsg = $"cmd={session.CurrentCommand},SessionID={session.SessionID},Md5={requestInfo.CheckSum},Uid={requestInfo.Uid},Key = {requestInfo.Key},Body={msgBody}";
            Logger.Trace(recvMsg);
            Console.WriteLine(recvMsg);
            switch (key)
            {
                case MsgTypes.Bye:
                    session.Close();
                    break;
                case MsgTypes.Echo:
                    //_client.Send(MsgPacket.CreateNewInstance(MsgTypes.Echo, DateTime.Now.ToString()).ToBytes());
                    Console.WriteLine(msgBody);
                    break;
                case MsgTypes.Ping:
                    session.PingReply(requestInfo);
                    Logger.Trace(key);
                    break;
                case MsgTypes.PingReply:
                    break;
                case MsgTypes.IISAdminRequest:
                    IISReqestHandler?.Invoke(session, new RequestArg(requestInfo));
                    break;
                case MsgTypes.IISAdminRespone:
                    IISResponeHandler?.Invoke(session, new ResponeArg(requestInfo));
                    break;
                case MsgTypes.Time:
                    session.TimeReply();
                    break;
                case MsgTypes.AppPoolInfoReply:
                    clientHandle.HandleAppPoolInfoAsync(requestInfo);
                    break;
                case MsgTypes.AppPoolAddReply:
                    clientHandle.HandleAppPoolAddAsync(requestInfo);
                    break;
                case MsgTypes.AppPoolEditReply:
                    clientHandle.HandleAppPoolEditAsync(requestInfo);
                    break;
                case MsgTypes.AppPoolDeleteReply:
                    clientHandle.HandleAppPoolDeleteAsync(requestInfo);
                    break;
                case MsgTypes.WebSiteInfoReply:
                    clientHandle.HandleWebSiteInfoAsync(requestInfo);
                    break;
                case MsgTypes.WebSiteAddReply:
                    clientHandle.HandleWebSiteAddAsync(requestInfo);
                    break;
                case MsgTypes.WebSiteEditReply:
                    clientHandle.HandleWebSiteEditAsync(requestInfo);
                    break;
                case MsgTypes.WebSiteDeleteReply:
                    clientHandle.HandleWebSiteDeleteAsync(requestInfo);
                    break;
                case MsgTypes.DownLoadReply:
                    clientHandle.HandleDownloadAsync(requestInfo);
                    break;
                case MsgTypes.UploadReply:
                    clientHandle.HandleUploadAsync(requestInfo);
                    break;
                case MsgTypes.GetVersionReply:
                    clientHandle.HandleGetVersionAsync(requestInfo);
                    break;
                case MsgTypes.CheckUpdateReply:
                    clientHandle.HandleCheckUpdateAsync(requestInfo);
                    break;
                case MsgTypes.CheckSiteNameReply:
                    clientHandle.HandleCheckSiteNameAsync(requestInfo);
                    break;
                default:
                    Logger.Error($"未知指令:{key}");
                    Console.WriteLine($"未知指令:{key}");
                    break;
            }
        }



        public void SetDbContext(IServiceScopeFactory service)
        {
            _scope = service.CreateScope();

            var services = _scope.ServiceProvider;
            _applicationDb = services.GetRequiredService<ApplicationDbContext>();


            //_applicationDb = context;
        }

        /// <summary>
        /// 通过客户端ID找Session
        /// </summary>
        /// <param name="id">客户端ID</param>
        /// <returns></returns>
        public UpdaterSocketSession GetSessionByClientId(string id)
        {
            return GetAllSessions().FirstOrDefault(w => w.ClientId == id);
        }

        private Models.ClientGroup DefaultGroup()
        {
            if (_applicationDb != null)
            {
                var defaultGroup = _applicationDb.ClientGroups.Find(0);
                if (defaultGroup != null)
                {
                    return defaultGroup;
                }
            }
            return new Models.ClientGroup
            {
                Id = 0,
                Name = "默认"
            };

        }
        private void IISAdminResponeHandler()
        {

        }
    }
}
